package app;


import java.util.*;

public class Instance {
	private List<AttributeValue> values;
	private AttributeSet attributeSet;
	
	public Instance(AttributeSet attributeSet) {
		if (attributeSet == null)
			throw new IllegalArgumentException("Invalid argument");
		
		this.attributeSet = attributeSet;
		values = new ArrayList<AttributeValue>();
	}
	
	// copy an instance without an attribute
	public Instance(Instance instance, int exceptAttributeIndex) {
		attributeSet = new AttributeSet(instance.getAttributeSet(), exceptAttributeIndex);

		values = new ArrayList<AttributeValue>();
		for (int i=0; i < instance.getValues().size(); i++) {
			if (i != exceptAttributeIndex)
				values.add(instance.getValue(i));
		}
	}

	public void populateWithUpdate(String[] stringValues) {
		if (stringValues == null)
			throw new IllegalArgumentException("Invalid argument");
		
		for (int i = 0; i < attributeSet.size(); i++) {
			if (attributeSet.get(i) instanceof NumericAttribute) {
				NumericAttribute attribute = (NumericAttribute) attributeSet.get(i);
				NumericValue attributeValue = attribute.addValue(Double.parseDouble(stringValues[i]));
				values.add(attributeValue);
			} else if (attributeSet.get(i) instanceof SymbolicAttribute) {
				SymbolicAttribute attribute = (SymbolicAttribute) attributeSet.get(i);
				SymbolicValue attributeValue = attribute.addValue(stringValues[i].trim());
				values.add(attributeValue);
			}
		}
	}
	
	/* 
	 * The function should throw an exception in the following cases:
	 * - for a symbolic attribute: the value is not in the attribute value list
	 * - for a numeric attribute: if not maxValue <= value <= minValues
	 */
	public void populateWithoutUpdate(String[] stringValues) {
		if (stringValues == null)
			throw new IllegalArgumentException("Invalid argument");
		
		for (int i = 0; i < attributeSet.size(); i++) {
			if (attributeSet.get(i) instanceof NumericAttribute) {
				double newValue = Double.parseDouble(stringValues[i]);
				NumericAttribute attribute = (NumericAttribute) attributeSet.get(i);
				// check the limits
				if (newValue < attribute.getMinValue().getValue() || newValue > attribute.getMaxValue().getValue())
					throw new IllegalArgumentException("Invalid numeric value!");
				
				NumericValue attributeValue = new NumericValue(newValue);
				values.add(attributeValue);
			} else if (attributeSet.get(i) instanceof SymbolicAttribute) {
				SymbolicAttribute attribute = (SymbolicAttribute) attributeSet.get(i);
				SymbolicValue attributeValue = attribute.findValue(stringValues[i].trim());
				// check if the value exits in the attribute value list
				// skip the check for the class attribute
				if (attributeValue == null && i != attributeSet.size() - 1)
					throw new IllegalArgumentException("Invalid symbolic value!");
				values.add(attributeValue);
			}
		}
	}
	
	public AttributeValue getValue(int index) {
		if (index < 0 || index > values.size())
			throw new IllegalArgumentException("Invalid index");
		
		return values.get(index);
	}
	
	public AttributeValue getValue(Attribute attribute) {
		return values.get(attributeSet.indexOf(attribute));
	}
	
	public AttributeSet getAttributeSet() {
		return attributeSet;
	}
	
	public List<AttributeValue> getValues() {
		return values;
	}

	public int noAttributes() {
		return values.size();
	}
	
	public String toString() {
		String str = "";
		
		for (AttributeValue value: values)
			str +=  value + " ";
		str += "\n";
		
		return str;
	}
}
